package www.sofn.com.accounts;

import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import www.sofn.com.accounts.domain.vo.WeChartMemberInfoVO;
import www.sofn.com.accounts.domain.vo.WeChatAccessTokenVO;
import www.sofn.com.accounts.domain.vo.WeChatUserInfoVO;
import www.sofn.com.config.properties.WeChatProperties;
import www.sofn.com.constant.Constants;
import www.sofn.com.exception.ValidateException;
import www.sofn.com.member.MemberService;
import www.sofn.com.member.domain.po.MemberPO;
import www.sofn.com.relation.MemberRelationService;
import www.sofn.com.relation.domain.pojo.MemberRelationPO;
import www.sofn.com.security.domain.vo.TokenInfoVO;
import www.sofn.com.security.service.TokenService;
import www.sofn.com.utils.ServletUtils;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
public class AccountsService {

    @Resource
    private RestTemplate restTemplate;
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private MemberService memberService;

    @Resource
    private WeChatProperties properties;

    @Resource
    private AuthenticationManager authenticationManager;

    //获取微信accessToken url
    private final static String ACCESS_TOKEN_URL = "/oauth2/access_token";

    //微信url前缀
    private final static String WECHAT_URL_PREFIX = "https://api.weixin.qq.com/sns";

    //拉取用户url
    private final static String USERINFO_URL = "/userinfo";

    @Autowired
    private TokenService tokenService;

    @Resource
    private MemberRelationService memberRelationService;

    /**
     * 微信用户登录
     *
     * @param code 用户同意授权返回的code
     * @return
     */
    public String weChatLogin(String code) {
        // 1.获取 access_token
        WeChatAccessTokenVO accessTokenVO = this.getAccessToken(code);
        if (StrUtil.isBlank(accessTokenVO.getAccess_token())) {
            throw new ValidateException("登录失败！");
        }
        //2.拉取微信用户信息
        WeChatUserInfoVO wxUserInfo = this.getWxUserInfo(accessTokenVO.getAccess_token(), accessTokenVO.getOpenid());
        //3.注册会员
        this.register(wxUserInfo);
        //写入 authentication
        Authentication authentication = null;
        try {
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(wxUserInfo.getOpenid(), ""));
        } catch (Exception e) {
            throw new ValidateException(e.getMessage());
        }
        final User user = (User) authentication.getPrincipal();
        Set<String> authorities = new HashSet<>();
        authorities.add("member");
        final String token = tokenService.createToken(new TokenInfoVO(user.getUsername(), authorities));
        return token;
    }


    public void register(WeChatUserInfoVO weChatUserInfoVO) {
        if (!memberService.exitOpenid(weChatUserInfoVO.getOpenid())) {
            memberService.registerMember(weChatUserInfoVO);
        }
    }

    /**
     * 获取 access_token
     *
     * @param code
     * @return
     */
    public WeChatAccessTokenVO getAccessToken(@RequestParam("code") String code) {
        UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromUriString(WECHAT_URL_PREFIX + ACCESS_TOKEN_URL);
        urlBuilder.queryParam("appid", properties.getAppId())
                .queryParam("secret", properties.getAppSecret())
                .queryParam("code", code)
                .queryParam("grant_type", "authorization_code");
        URI uri = URI.create(urlBuilder.toUriString());
        String resultStr = restTemplate.getForObject(uri, String.class);
        return JSONUtil.toBean(resultStr, WeChatAccessTokenVO.class);
    }

    /**
     * 拉取微信用户信息
     *
     * @param accessToken
     * @param openid
     * @return
     */
    public WeChatUserInfoVO getWxUserInfo(String accessToken, String openid) {
        UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromUriString(WECHAT_URL_PREFIX + USERINFO_URL);
        urlBuilder.queryParam("access_token", accessToken)
                .queryParam("openid", openid)
                .queryParam("lang", "zh_CN");
        URI uri = URI.create(urlBuilder.toUriString());
        String resultStr = restTemplate.getForObject(uri, String.class);
        final WeChatUserInfoVO weChatUserInfoVO = JSONUtil.toBean(resultStr, WeChatUserInfoVO.class);
        weChatUserInfoVO.setNickname(transcoding(weChatUserInfoVO.getNickname()));
        return weChatUserInfoVO;
    }

    /**
     * 昵称转换
     *
     * @param str
     * @return
     */
    private String transcoding(String str) {
        if (StrUtil.isBlank(str)) return "";
        byte[] bytes = str.getBytes(StandardCharsets.ISO_8859_1);
        // 使用UTF-8重新编码为正常的字符串
        return new String(bytes, StandardCharsets.UTF_8);
    }

    public WeChartMemberInfoVO getPersonal() {
        final TokenInfoVO tokenInfo = tokenService.getTokenInfo(ServletUtils.getRequest());
        if (ObjectUtil.isNull(tokenInfo)) return null;
        String openid = tokenInfo.getUsername();
        //查询会员表
        final MemberPO memberPO = memberService.getMemberByOpenid(openid);
        return BeanUtil.toBean(memberPO, WeChartMemberInfoVO.class);
    }

    public String generateCommand() {
        final WeChartMemberInfoVO personal = getPersonal();
        if (personal.getIsMember()) {
            RandomGenerator randomGenerator = new RandomGenerator(6);
            String command = randomGenerator.generate();
            redisTemplate.opsForValue().set(Constants.COMMAND_PREFIX + command, personal.getId(), 5, TimeUnit.MINUTES);
            return command;
        }
        return null;
    }


    @Transactional
    public void buildRelation(String command){
        final String superiorMemberId = redisTemplate.opsForValue().get(Constants.COMMAND_PREFIX + command);
        if(StrUtil.isBlank(superiorMemberId)){
            throw new ValidateException("建立关系失败：口令错误!");
        }
        final WeChartMemberInfoVO personal = getPersonal();
        if(personal.getIsMember()){
            throw new ValidateException("建立关系失败：该用户已经建立关系！");
        }
        memberService.makeMember(personal.getId());//修改会员表状态
        //建立关系
        memberRelationService.save(new MemberRelationPO().setMemberId(Long.valueOf( personal.getId())).setSuperiorMemberId(Long.valueOf(superiorMemberId)));
        redisTemplate.delete(Constants.COMMAND_PREFIX + command);
    }
}
